package cn.coco.jf.fw.api.render;

import java.util.HashMap;
import java.util.Map;

import cn.exlu.coco.core.utils.QrcodeUtil;

import com.google.zxing.EncodeHintType;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.jfinal.kit.StrKit;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

/**
 * QrCodeRender 生成二维码
 */
public class JkQrcodeRender extends Render {

    private String content;
    private String txt;
    private Integer width;
    private Integer height;
    private ErrorCorrectionLevel errorCorrectionLevel;

    /**
     * 构造方法，经测试不指定纠错参数时，默认使用的是 'L' 最低级别纠错参数
     * @param content 二维码携带内容
     * @param width 二维码宽度
     * @param height 二维码高度
     */
    public JkQrcodeRender(String content, String txt, Integer width, Integer height) {
        init(content, txt, width, height, null);
    }

    /**
     * 带有纠错级别参数的构造方法，生成带有 logo 的二维码采用纠错原理
     * 使用 ErrorCorrectionLevel.H 参数提升纠错能力
     *
     * ErrorCorrectionLevel 是枚举类型，纠错能力从高到低共有四个级别：
     *  H = ~30% correction
     *  Q = ~25% correction
     *  M = ~15% correction
     *  L = ~7%
     *
     *  使用的时候直接这样：ErrorCorrectionLevel.H
     */
    public JkQrcodeRender(String content, String txt, Integer width, Integer height, ErrorCorrectionLevel errorCorrectionLevel) {
        init(content, txt, width, height, errorCorrectionLevel);
    }

    /**
     * 带有纠错级别参数的构造方法，纠错能力从高到低共有四个级别：'H'、'Q'、'M'、'L'
     */
    public JkQrcodeRender(String content, String txt, Integer width, Integer height, char errorCorrectionLevel) {
        init(content, txt, width, height, errorCorrectionLevel);
    }

    private void init(String content, String txt, Integer width, Integer height, char errorCorrectionLevel) {
        if (errorCorrectionLevel == 'H') {
            init(content, txt, width, height, ErrorCorrectionLevel.H);
        } else if (errorCorrectionLevel == 'Q') {
            init(content, txt, width, height, ErrorCorrectionLevel.Q);
        } else if (errorCorrectionLevel == 'M') {
            init(content, txt, width, height, ErrorCorrectionLevel.M);
        } else if (errorCorrectionLevel == 'L') {
            init(content, txt, width, height, ErrorCorrectionLevel.L);
        } else {
            throw new IllegalArgumentException("errorCorrectionLevel 纠错级别参数值，从高到低必须为： 'H'、'Q'、'M'、'L'");
        }
    }

    private void init(String content, String txt, Integer width, Integer height, ErrorCorrectionLevel errorCorrectionLevel) {
        if (StrKit.isBlank(content)) {
            throw new IllegalArgumentException("content 不能为空");
        }
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("width 与 height 不能小于 0");
        }
        this.content = content;
        this.txt = txt;
        this.width = width;
        this.height = height;
        this.errorCorrectionLevel = errorCorrectionLevel;
    }

    public void render() {
        response.setHeader("Pragma","no-cache");
        response.setHeader("Cache-Control","no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/png");

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);    //去掉白色边框，极度重要，否则二维码周围的白边会很宽
        if (errorCorrectionLevel != null) {
            hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
        }

        try {
            // MultiFormatWriter 可支持多种格式的条形码，在此直接使用 QRCodeWriter，通过查看源码可知少创建一个对象
            // BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
            
            QrcodeUtil.qrcode_text(response.getOutputStream(), this.content, this.txt, 16, width, height, hints);

//            QRCodeWriter writer = new QRCodeWriter();
//            BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
//
//            // 经测试 200 X 200 大小的二维码使用 "png" 格式只有 412B，而 "jpg" 却达到 15KB
//            MatrixToImageWriter.writeToStream(bitMatrix, "png", response.getOutputStream());    // format: "jpg"、"png"
        }catch (Exception e) {
            throw new RenderException(e);
        }
    }
}

